//
// @Author: zhengqi Wu
// @Description:
// @Version: 1.0.0
// @Date: 2021/3/12 13:24
// @Copyright: MIN-Group；国家重大科技基础设施——未来网络北大实验室；深圳市信息论与未来网络重点实验室
//


function toHexChar(n){
    return "0123456789ABCDEF"[n&0xf]
}

function fromHexToChar(c){
    let res = 0
    switch (true){
        case c >= '0' && c <= '9':
            res = c.charCodeAt(0) - 48
            break
        case c >= 'a' && c <= 'f':
            res = c.charCodeAt(0) - 97 + 10
            break
        case c >= 'A' && c <= 'F':
            res = c.charCodeAt(0) - 65 + 10
            break
        default:
            res = 100
    }
    return res
}

/**
 * @description: 对字符串实施百分号编码
 *  1. 具体编码的定义参见：RFC 3986 section 2
 //	2. 将除了字母（'a'~'z', 'A'~'Z'）、数字（'0' ~ '9'）和指定特殊字符（'-', '.', '_', '~'）
 //	   之外的所有字符都进行百分号编码。
 //	3. 对字符串中的每个UTF-8字符c（用八位一个字节表示）进行如下规则的编码：
 //	   a. 首先将一个八位字节分为两个部分，hi = (c % 0xf0) >> 4 ; lo = c % 0xf。hi 和 lo 均为两个字节表示的数字，范围为（0~15）
 //	   b. 然后分别用 hi 和 lo 作为索引，从 "0123456789ABCDEF" 字符串取指定位置的字符，最后编码的结果如下表示：
 //	      '%' + "0123456789ABCDEF"[hi] + "0123456789ABCDEF"[lo]
 //	   c. 相当于每个需要编码的字符都编码成了一个%开头的三个字符表示
 * @param str
 * @returns 编码后字符串 {string}
 */
function escape(str){
    return escapeToWriter(str)
}

function escapeToWriter(str){
    let res = ''
    for(let i = 0; i < str.length; i++){
        let ch = str[i]
        if((ch >= 'a' && ch <= 'z') ||
            (ch >= 'A' && ch <= 'Z') ||
            (ch >= '0' && ch <= '9') ||
            ch === '-' || ch === '.' ||
            ch === '_' || ch === '~') {
            res += ch
        }else {
            let newStr = ''
            let tmpBuf = Buffer.from(ch, 'utf-8') // 获得字符的utf-8编码
            for(let j = 0; j < tmpBuf.length; j++){
                newStr += '%'
                newStr += toHexChar((tmpBuf[j] & 0xf0) >> 4)
                newStr += toHexChar((tmpBuf[j] & 0xf))
            }
            res += newStr
        }
    }
    return res
}

/**
 * @description 对字符串实施百分号解码
 * @param string
 * @returns {string}
 */
function unescape(string){
    let len = expectUnescapeBufLength(string)
    let buf = Buffer.alloc(len)
    unescapeToWriter(buf, string)
    return buf.toString('utf-8')
}

/**
 * 根据字符串测量Buffer大小
 * @param str
 * @returns {number}
 */

function expectUnescapeBufLength(str){
    let len = 0
    for(let i = 0; i < str.length; i++){
        let ch = str[i]
        if(ch === '%' && i + 2 < str.length){
            len += 1
            i += 2
        }else{
            len += 1
        }
    }
    return len
}

function unescapeToWriter(buf, str){
    let index = 0
    for(let i = 0; i < str.length; i++){
        let ch = str[i]
        if(ch === '%' && i + 2 < str.length){
            let hi = fromHexToChar(str[i+1])
            let lo = fromHexToChar(str[i+2])

            if(hi === 100 || lo === 100){
                buf.fill(ch, index, index+1)
            }else{
                buf.fill((hi << 4) | lo, index, index+1)
            }
            index += 1
            i += 2
        }else{
            buf.fill(ch, index, index+1)
            index += 1
        }
    }
}

module.exports = {
    'escape': escape,
    'unescape': unescape
}